//width:43 height:47
const unsigned char d1[] =
{
    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
    0xFF,0xFF,0xFF,0xFF,0xFF,0x80,0x00,0x7F,0xFF,0xFF,0xFF,0x80,0x00,0x7F,0xFF,0xFF,
    0xFE,0x00,0x00,0x1F,0xFF,0xFF,0xFE,0x18,0x00,0x1F,0xFF,0xFF,0xFE,0x18,0x00,0x1F,
    0xFF,0xFF,0xFE,0x00,0x00,0x1F,0xFF,0xFF,0xFE,0x00,0x00,0x1F,0xFF,0xFF,0xFE,0x00,
    0x00,0x1F,0xFF,0xFF,0xFE,0x00,0x00,0x1F,0xFF,0xFF,0xFE,0x00,0x00,0x1F,0xFF,0xFF,
    0xFE,0x00,0x00,0x1F,0xFF,0xFF,0xFE,0x00,0x7F,0xFF,0xFF,0xFF,0xFE,0x00,0x7F,0xFF,
    0xFF,0xFF,0xFE,0x00,0x01,0xFF,0xFF,0xFF,0xFE,0x00,0x01,0xFF,0xE7,0xFF,0xF8,0x01,
    0xFF,0xFF,0xE7,0xFF,0xF8,0x01,0xFF,0xFF,0xE7,0xFF,0xC0,0x01,0xFF,0xFF,0xE7,0xFF,
    0xC0,0x01,0xFF,0xFF,0xE1,0xFE,0x00,0x00,0x1F,0xFF,0xE1,0xFE,0x00,0x00,0x1F,0xFF,
    0xE0,0x78,0x00,0x01,0x9F,0xFF,0xE0,0x78,0x00,0x01,0x9F,0xFF,0xE0,0x00,0x00,0x01,
    0xFF,0xFF,0xE0,0x00,0x00,0x01,0xFF,0xFF,0xE0,0x00,0x00,0x01,0xFF,0xFF,0xE0,0x00,
    0x00,0x01,0xFF,0xFF,0xF8,0x00,0x00,0x01,0xFF,0xFF,0xF8,0x00,0x00,0x07,0xFF,0xFF,
    0xFE,0x00,0x00,0x07,0xFF,0xFF,0xFE,0x00,0x00,0x07,0xFF,0xFF,0xFF,0x80,0x00,0x1F,
    0xFF,0xFF,0xFF,0x80,0x00,0x1F,0xFF,0xFF,0xFF,0xE0,0x00,0x7F,0xFF,0xFF,0xFF,0xE0,
    0x00,0x7F,0xFF,0xFF,0xFF,0xF8,0x1E,0x0F,0xFF,0xFF,0xFF,0xF8,0x1E,0x0F,0xFF,0xFF,
    0xFF,0xF8,0x7F,0xFF,0xFF,0xFF,0xFF,0xF8,0x7F,0xFF,0xFF,0xFF,0xFF,0xF9,0xFF,0xFF,
    0xFF,0xFF,0xFF,0xF9,0xFF,0xFF,0xFF,0xFF,0xFF,0xF8,0x7F,0xFF,0xFF,0xFF,0xFF,0xF8,
    0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
};

const unsigned char d2[] =
{
    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x80,0x00,0x7F,0xFF,0xFF,
    0xFF,0x80,0x00,0x7F,0xFF,0xFF,0xFE,0x00,0x00,0x1F,0xFF,0xFF,0xFE,0x18,0x00,0x1F,
    0xFF,0xFF,0xFE,0x18,0x00,0x1F,0xFF,0xFF,0xFE,0x00,0x00,0x1F,0xFF,0xFF,0xFE,0x00,
    0x00,0x1F,0xFF,0xFF,0xFE,0x00,0x00,0x1F,0xFF,0xFF,0xFE,0x00,0x00,0x1F,0xFF,0xFF,
    0xFE,0x00,0x00,0x1F,0xFF,0xFF,0xFE,0x00,0x00,0x1F,0xFF,0xFF,0xFE,0x00,0x7F,0xFF,
    0xFF,0xFF,0xFE,0x00,0x7F,0xFF,0xFF,0xFF,0xFE,0x00,0x01,0xFF,0xFF,0xFF,0xFE,0x00,
    0x01,0xFF,0xE7,0xFF,0xF8,0x01,0xFF,0xFF,0xE7,0xFF,0xF8,0x01,0xFF,0xFF,0xE7,0xFF,
    0xC0,0x01,0xFF,0xFF,0xE7,0xFF,0xC0,0x01,0xFF,0xFF,0xE1,0xFE,0x00,0x00,0x1F,0xFF,
    0xE1,0xFE,0x00,0x00,0x1F,0xFF,0xE0,0x78,0x00,0x01,0x9F,0xFF,0xE0,0x78,0x00,0x01,
    0x9F,0xFF,0xE0,0x00,0x00,0x01,0xFF,0xFF,0xE0,0x00,0x00,0x01,0xFF,0xFF,0xE0,0x00,
    0x00,0x01,0xFF,0xFF,0xE0,0x00,0x00,0x01,0xFF,0xFF,0xF8,0x00,0x00,0x01,0xFF,0xFF,
    0xF8,0x00,0x00,0x07,0xFF,0xFF,0xFE,0x00,0x00,0x07,0xFF,0xFF,0xFE,0x00,0x00,0x07,
    0xFF,0xFF,0xFF,0x80,0x00,0x1F,0xFF,0xFF,0xFF,0x80,0x00,0x1F,0xFF,0xFF,0xFF,0xE0,
    0x00,0x7F,0xFF,0xFF,0xFF,0xE0,0x00,0x7F,0xFF,0xFF,0xFF,0xF8,0x78,0x7F,0xFF,0xFF,
    0xFF,0xF8,0x78,0x7F,0xFF,0xFF,0xFF,0xFE,0x1E,0x7F,0xFF,0xFF,0xFF,0xFE,0x1E,0x7F,
    0xFF,0xFF,0xFF,0xFF,0xFE,0x7F,0xFF,0xFF,0xFF,0xFF,0xFE,0x7F,0xFF,0xFF,0xFF,0xFF,
    0xFE,0x1F,0xFF,0xFF,0xFF,0xFF,0xFE,0x1F,0xFF,0xFF,
};

String ssidList; // ssid列表
boolean restoreConfig()
{
    Serial.println("Reading EEPROM...");
    if (EEPROM.read(4000) != 0)
    {
        ssid = "";
        pass = "";
        authcode = "";
        for (int i = 4000; i < 4032; ++i)
        {
            char ch = EEPROM.read(i);
            // if (isalpha(ch) || isdigit(ch))
            if (ch!=0) ssid += char(EEPROM.read(i));
        }
        Serial.print("WiFi: ");
        Serial.println(ssid);
        for (int i = 4032; i < 4064; ++i)
        {
            char ch = EEPROM.read(i);
            // if (isalpha(ch) || isdigit(ch))
            if (ch!=0) pass += char(EEPROM.read(i));
        }
        Serial.print("密码: ");
        Serial.println(pass);
        for (int i = 4064; i < 4096; ++i)
        {
            char ch = EEPROM.read(i);
            // if (isalpha(ch) || isdigit(ch) || ch == '-'|| ch == '_')
            if (ch!=0) authcode += char(EEPROM.read(i));
        }
        if(authcode=="")
        {
            authcode=authcode_default;
        }
        Serial.print("密钥: ");
        Serial.println(authcode);
        WiFi.begin(ssid.c_str(), pass.c_str());
        return true;
    }
    else
    {
        Serial.println("Config not found.");
        return false;
    }
}
boolean setDefaultConfig()
{
  Serial.println("clear eeprom.");

   for (int i = 4000; i < 4096; ++i) {
      EEPROM.begin(4096);
      EEPROM.write(i, 0);
      EEPROM.commit();
    }
    EEPROM.end();
    ESP.restart();


}

boolean checkConnection()
{
    int ckcount = 0;
    int tip_x=32,tip_y=48;
  
    display.setFullWindow();
    display.fillScreen(GxEPD_WHITE);
    u8g2Fonts.setFontMode(1);                   // use u8g2 transparent mode (this is default)
    u8g2Fonts.setFontDirection(0);              // left to right (this is default)
    u8g2Fonts.setFont(chinese_city_gb2312);
    u8g2Fonts.setForegroundColor(GxEPD_BLACK);  // 设置前景色
    u8g2Fonts.setBackgroundColor(GxEPD_WHITE);  // 设置背景色
    u8g2Fonts.setCursor(32,32);
    u8g2Fonts.print("启动中 . . .");
    display.drawInvertedBitmap(42, 52, d1, 43, 47, GxEPD_BLACK);
    display.nextPage();
    display.setPartialWindow(42, 52, 43, 47);   //仅局部刷新时间
    Serial.println("正在等待连接");
    setButtonCount=0;
    while (ckcount < 50)
    {
        if (WiFi.status() == WL_CONNECTED)
        {
            Serial.println("成功连接！");
            return (true);
        }
        if (ckcount%2==0)
        {
            u8g2Fonts.setCursor(tip_x,tip_y);
            tip_x+=8;
            if(tip_x>180){
              tip_x = 32;
              tip_y+=16;
            }
            u8g2Fonts.print(".");
            display.fillRect(42, 52, 43, 47, GxEPD_WHITE);
            display.drawInvertedBitmap(42, 52, d2, 43, 47, GxEPD_BLACK);
        }
        else
        {
           display.fillRect(42, 52, 43, 47, GxEPD_WHITE);
          display.drawInvertedBitmap(42, 52, d1, 43, 47, GxEPD_BLACK);
        }
        display.nextPage();
        //check set pin 
         //btn control
        setButtonState = digitalRead(setPin);  //按键
        if (setButtonState == LOW) {
        
          setButtonState_t = LOW;
          setButtonCount++;
          delay(50);
        } else {
          if (setButtonState_t == LOW) {
            if (setButtonCount > 40) {
              Serial.println("wifi connect set长按, ");
              //exit
              return false;
            
            } 
          }
          setButtonCount = 0;
          setButtonState_t = HIGH;
        }

        delay(10);
        if(ckcount%5==0) Serial.print(".");
        ckcount++;
    }
    Serial.println("连接超时.");
    return false;
}

String makePage(String title, String contents)
{
    String s = "<!DOCTYPE html><html><head>";
    s += "<meta name=\"viewport\" content=\"width=device-width,user-scalable=0\">";
    s += "<title>";
    s += title;
    s += "</title></head><body>";
    s += contents;
    s += "</body></html>";
    return s;
}

String urlDecode(String input)
{
    String s = input;
    s.replace("%20", " ");
    s.replace("+", " ");
    s.replace("%21", "!");
    s.replace("%22", "\"");
    s.replace("%23", "#");
    s.replace("%24", "$");
    s.replace("%25", "%");
    s.replace("%26", "&");
    s.replace("%27", "\'");
    s.replace("%28", "(");
    s.replace("%29", ")");
    s.replace("%30", "*");
    s.replace("%31", "+");
    s.replace("%2C", ",");
    s.replace("%2E", ".");
    s.replace("%2F", "/");
    s.replace("%2C", ",");
    s.replace("%3A", ":");
    s.replace("%3A", ";");
    s.replace("%3C", "<");
    s.replace("%3D", "=");
    s.replace("%3E", ">");
    s.replace("%3F", "?");
    s.replace("%40", "@");
    s.replace("%5B", "[");
    s.replace("%5C", "\\");
    s.replace("%5D", "]");
    s.replace("%5E", "^");
    s.replace("%5F", "-");
    s.replace("%60", "`");
    return s;
}

void startWebServer()
{
    if (settingMode)
    {
        Serial.print("Starting Web Server at ");
        Serial.println(WiFi.softAPIP());
        webServer.on("/settings", []()
        {
            String s = "<head><meta charset=\"utf-8\"></head><h1>DeaInk Wi-Fi配置</h1><p>请在选择WiFi名称后输入对应的WiFi密码</p>";
            s += "<form method=\"get\" action=\"setap\"><label>网络:</label><select name=\"ssid\">";
            s += ssidList;
            s += "</select><br>密码:<input name=\"pass\" length=64 type=\"password\">";
            s += "<p>首次使用务必填写心知密钥</p>";
            s += "<form method=\"get\" action=\"setconfig\">心知密钥:<input name=\"authcode\" length=64 type=\"password\"><br>";
            s += "<input name=\"保存并提交\"  type=\"submit\"></form>";
            webServer.send(200, "text/html", makePage("日历Wi-Fi配置", s)); 
        });
        webServer.on("/setap", []()
        {
            //清空数据，防止出现WiFi账号密码长度不一致导致的无法联网问题
            for (int i = 4000; i < 4064; ++i) {
                EEPROM.begin(4096);
                EEPROM.write(i, 0);
                EEPROM.commit();
            }
            ssid = urlDecode(webServer.arg("ssid"));
            Serial.print("SSID: ");
            Serial.println(ssid);
            pass = urlDecode(webServer.arg("pass"));
            Serial.print("Password: ");
            Serial.println(pass);
            String authcode_t = urlDecode(webServer.arg("authcode"));
            Serial.print("Authcode: ");
            Serial.println(authcode);
            Serial.println("Writing ssid to EEPROM...");
            for (int i = 0; i < ssid.length(); ++i) {
                EEPROM.begin(4096);
                EEPROM.write(4000 + i, ssid[i]);
                EEPROM.commit();
            }
            for (int i = 0; i < pass.length(); ++i) {
                EEPROM.begin(4096);
                EEPROM.write(4032 + i, pass[i]);
                EEPROM.commit();
            }
            if(authcode_t!="")
            {
                for (int i = 4064; i < 4096; ++i) {
                    EEPROM.begin(4096);
                    EEPROM.write(i, 0);
                    EEPROM.commit();
                }
                authcode = authcode_t;
                for (int i = 0; i < authcode.length(); ++i) {
                    EEPROM.begin(4096);
                    EEPROM.write(4064 + i, authcode[i]);
                    EEPROM.commit();
                } 
            }
            Serial.println("Writing to EEPROM...");
            EEPROM.end();
            String s = "<head><meta charset=\"utf-8\"></head><h1>设置结束！</h1><p>设备即将在重启后接入 \"";
            s += ssid;
            s += "\" ";
            webServer.send(200, "text/html", makePage("日历Wi-Fi配置", s));
            ESP.restart(); 
         });
        webServer.onNotFound([]()
        {
            String s = "<head><meta charset=\"utf-8\"></head><h1>配网模式</h1><p><a href=\"/settings\">点击配网</a></p>";
            webServer.send(200, "text/html", makePage("配网模式", s)); 
        });
    }
    webServer.begin();
}

void configWebServer()
{
    Serial.print("Config Web Server at ");
    Serial.println(WiFi.localIP());
    webServer.on("/", []()
    {
        String s = "<head><meta charset=\"utf-8\"><h1>配置界面</h1><p>仅永久保存心知密钥</p>";
        s+="<form method=\"get\" action=\"setconfig\"><br>心知密钥:<input name=\"authcode\" length=64 type=\"password\">";
        s+="<br>NTP服务器:<input name=\"ntpServer\" length=64 type=\"password\">";  
        s+="<br>时区:<input name=\"timezone_offset\" length=64 type=\"password\">";         
        s+="<br>诗词Token:<input name=\"token\" length=64 type=\"password\"><br><br>";    
        s += "<input name=\"保存并提交\"  type=\"submit\"></form>";  
        webServer.send(200, "text/html", makePage("配置界面", s)); 
     });
    webServer.on("/setconfig", []()
    {
        for (int i = 4064; i < 4096; ++i) {
            EEPROM.begin(4096);
            EEPROM.write(i, 0);
            EEPROM.end();
        }
        String authcode_t = urlDecode(webServer.arg("authcode"));
        if(authcode_t!="")
        {
            authcode=authcode_t;
            Serial.print("authcode: ");
            Serial.println(authcode);
            for (int i = 0; i < authcode.length(); ++i) {
                EEPROM.begin(4096);
                EEPROM.write(4064 + i, authcode[i]);
                EEPROM.commit();
            }
            EEPROM.end();
            Serial.println("Write EEPROM done!");
        }
        /*
        Serial.print("authcode: ");
        Serial.println(authcode);
        for (int i = 0; i < authcode.length(); ++i) {
            EEPROM.begin(4096);
            EEPROM.write(4064 + i, authcode[i]);
            EEPROM.commit();
        }
        EEPROM.end();
        Serial.println("Write EEPROM done!");
        */
        String ntpServerName_t = urlDecode(webServer.arg("ntpServer"));
        if(ntpServerName_t!="") 
        {
            int i;
            for (i = 0; i < ntpServerName_t.length(); i++) 
            {
              ntpServerName[i] = ntpServerName_t[i];
            }
            ntpServerName[i] = '\0';
        }
        String timezone_offset_t = urlDecode(webServer.arg("timezone_offset"));
        if(timezone_offset_t!="") timezone_offset = atoi(timezone_offset_t.c_str());  
        String shici_token_t = urlDecode(webServer.arg("token"));
        firstFlag = true;
        //if(shici_token_t!="") strcpy(shici_token, shici_token_t.c_str());         
        String s = "<head><meta charset=\"utf-8\"></head><h1>设置已重置</h1>";
        webServer.send(200, "text/html", makePage("Settings", s)); 
    });
    webServer.begin();
}

void setupMode()
{
    Serial.println("wifi setup.");

    WiFi.mode(WIFI_STA);
    Serial.println("wifi STATION mode.");
    WiFi.disconnect();
    Serial.println("wifi disconnect.");

    delay(100);
    int n = WiFi.scanNetworks();
    Serial.printf("wifi count:%d.\n",n);

    delay(100);
    Serial.println("");
    for (int i = 0; i < n; ++i)
    {
        ssidList += "<option value=\"";
        ssidList += WiFi.SSID(i);
        ssidList += "\">";
        ssidList += WiFi.SSID(i);
        ssidList += "</option>";
    }
    delay(100);
    WiFi.mode(WIFI_AP);
    Serial.println("wifi AP mode.");

    WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
    WiFi.softAP(apSSID);
    dnsServer.start(53, "*", apIP);
    startWebServer();
    Serial.print("Starting Access Point at \"");
    Serial.print(apSSID);
    Serial.println("\"");
}

void SmartConfig()               //微信配网是通过SmartConfig方法来实现的
{
    WiFi.mode(WIFI_AP_STA);
    WiFi.beginSmartConfig();                         //开始SmartConfig，等待手机端发出用户名和密码
    Serial.println("Waiting for Smartconfig...");    //打印log信息     

    while (!WiFi.smartConfigDone()) {
      delay(500);
      Serial.print(".");
    } 
    Serial.println("");
    Serial.println("SmartConfig received.");
    
    //Wait for WiFi to connect to AP
    Serial.println("Waiting for WiFi");
    while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
    }   
    Serial.println("WiFi Connected.");
    ssid=WiFi.SSID().c_str();
    pass=WiFi.psk().c_str();
    Serial.printf("SSID:%s\r\n", ssid);
    Serial.printf("PSW:%s\r\n", pass);
    for (int i = 4000; i < 4064; ++i) {
        EEPROM.begin(4096);
        EEPROM.write(i, 0);
        EEPROM.commit();
    }
    Serial.println("Writing ssid to EEPROM...");
    for (int i = 0; i < ssid.length(); ++i) {
        EEPROM.begin(4096);
        EEPROM.write(4000 + i, ssid[i]);
        EEPROM.commit();
    }
    Serial.println("Writing Password to EEPROM...");
    for (int i = 0; i < pass.length(); ++i) {
        EEPROM.begin(4096);
        EEPROM.write(4032 + i, pass[i]);
        EEPROM.commit();
    }
    EEPROM.end();
    delay(1000);
    ESP.restart();
}

void wifi_init()
{
    if (restoreConfig())
    {
        if (checkConnection())
        {
            settingMode = false;
            return;
        }
    }
    settingMode = true;
}
